#include "stdafx.h"
#include "net/NTPPacket.hpp"
#include "charset/byteorder.hpp"
using JHCPP::charset::CByteOrder;

NET_NAMESPACE_BEGIN

#pragma pack(push,1)
typedef struct _NTPPacketData {
	Int8 mode:3;
	Int8 vn:3;
	Int8 li:2;
	Int8 stratum;
	Int8 pool;
	Int8 prec;
	Int32 rootdelay;
	Int32 rootdisp;
	Int32 refid;
	Int64 rts;
	Int64 ots;
	Int64 vts;
	Int64 tts;
} NTPPacketData;
#pragma pack(pop)


CNTPPacket::CNTPPacket()
	: m_leapIndicator(3),
	m_version(4),
	m_mode(3),

	m_stratum(0),
	m_pool(6),
	m_precision(-18),
	m_rootDelay(0),
	m_rootDispersion(0),
	m_referenceId(0),
	m_referenceTimestamp(0),
	m_receiveTimestamp(0),
	m_transmitTimestamp(0)
{
	CTimeStamp ts;
	m_originateTimestamp = ts.utcTime();
}


CNTPPacket::CNTPPacket(UInt8 *packet)
{
	setPacket(packet);
}

CNTPPacket::~CNTPPacket()
{
}

void CNTPPacket::packet(UInt8 *packet) const
{
	NTPPacketData *p = (NTPPacketData*)packet;

	p->li = m_leapIndicator;
	p->vn = m_version;
	p->mode = m_mode;
	p->stratum = m_stratum;
	p->pool = m_pool;
	p->prec = m_precision;
	p->rootdelay = CByteOrder::toNetwork(m_rootDelay);
	p->rootdisp = CByteOrder::toNetwork(m_rootDispersion);
	p->refid = CByteOrder::toNetwork(m_referenceId);
	p->rts = CByteOrder::toNetwork(m_referenceTimestamp);
	p->ots = CByteOrder::toNetwork(m_originateTimestamp);
	p->vts = CByteOrder::toNetwork(m_receiveTimestamp);
	p->tts = CByteOrder::toNetwork(m_transmitTimestamp);
}

void CNTPPacket::setPacket(UInt8 *packet)
{
	NTPPacketData *p = (NTPPacketData*)packet;

	m_leapIndicator = p->li;
	m_version = p->vn;
	m_mode = p->mode;
	m_stratum = p->stratum;
	m_pool = p->pool;
	m_precision = p->prec;
	m_rootDelay = CByteOrder::fromNetwork(p->rootdelay);
	m_rootDispersion = CByteOrder::fromNetwork(p->rootdisp);
	m_referenceId = CByteOrder::fromNetwork(p->refid);
	m_referenceTimestamp = CByteOrder::fromNetwork(p->rts);
	m_originateTimestamp = CByteOrder::fromNetwork(p->ots);
	m_receiveTimestamp = CByteOrder::fromNetwork(p->vts);
	m_transmitTimestamp = CByteOrder::fromNetwork(p->tts);
}

CTimeStamp CNTPPacket::referenceTime() const
{
	return convertTime(m_referenceTimestamp);
}

CTimeStamp CNTPPacket::originateTime() const
{
	return convertTime(m_originateTimestamp);
}

CTimeStamp CNTPPacket::receiveTime() const
{
	return convertTime(m_receiveTimestamp);
}

CTimeStamp CNTPPacket::transmitTime() const
{
	return convertTime(m_transmitTimestamp);
}

CTimeStamp CNTPPacket::convertTime(Int64 tm) const
{
	const unsigned long seventyYears = 2208988800UL;
	UInt32 secsSince1900 = UInt32(CByteOrder::toLittleEndian(tm) >> 32);
	unsigned long epoch = secsSince1900 - seventyYears;
	return CTimeStamp::fromEpochTime(epoch);
}

Int8 CNTPPacket::leapIndicator() const
{
	return m_leapIndicator;
}

Int8 CNTPPacket::version() const
{
	return m_version;
}

Int8 CNTPPacket::mode() const
{
	return m_mode;
}

Int8 CNTPPacket::stratum() const
{
	return m_stratum;
}

Int8 CNTPPacket::pool() const
{
	return m_pool;
}

Int8 CNTPPacket::precision() const
{
	return m_precision;
}

Int32 CNTPPacket::rootDelay() const
{
	return m_rootDelay;
}

Int32 CNTPPacket::rootDispersion() const
{
	return m_rootDispersion;
}

Int32 CNTPPacket::referenceId() const
{
	return m_referenceId;
}

Int64 CNTPPacket::referenceTimestamp() const
{
	return m_referenceTimestamp;
}

Int64 CNTPPacket::originateTimestamp() const
{
	return m_originateTimestamp;
}

Int64 CNTPPacket::receiveTimestamp() const
{
	return m_receiveTimestamp;
}

Int64 CNTPPacket::transmitTimestamp() const
{
	return m_transmitTimestamp;
}


NET_NAMESPACE_END
